Changed FrontendActionFactory::create to return a std::unique_ptr
[lldb.git] / clang-tools-extra / clangd / unittests / SymbolCollectorTests.cpp
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/Tooling/Tooling.h"
18 #include "llvm/ADT/IntrusiveRefCntPtr.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/VirtualFileSystem.h"
23 #include "gmock/gmock-matchers.h"
24 #include "gmock/gmock-more-matchers.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27
28 #include <memory>
29 #include <string>
30
31 namespace clang {
32 namespace clangd {
33 namespace {
34
35 using ::testing::_;
36 using ::testing::AllOf;
37 using ::testing::Contains;
38 using ::testing::Each;
39 using ::testing::ElementsAre;
40 using ::testing::Field;
41 using ::testing::Not;
42 using ::testing::Pair;
43 using ::testing::UnorderedElementsAre;
44 using ::testing::UnorderedElementsAreArray;
45
46 // GMock helpers for matching Symbol.
47 MATCHER_P(Labeled, Label, "") {
48   return (arg.Name + arg.Signature).str() == Label;
49 }
50 MATCHER_P(ReturnType, D, "") { return arg.ReturnType == D; }
51 MATCHER_P(Doc, D, "") { return arg.Documentation == D; }
52 MATCHER_P(Snippet, S, "") {
53   return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
54 }
55 MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
56 MATCHER_P(TemplateArgs, TemplArgs, "") {
57   return arg.TemplateSpecializationArgs == TemplArgs;
58 }
59 MATCHER_P(DeclURI, P, "") {
60   return StringRef(arg.CanonicalDeclaration.FileURI) == P;
61 }
62 MATCHER_P(DefURI, P, "") { return StringRef(arg.Definition.FileURI) == P; }
63 MATCHER(IncludeHeader, "") { return !arg.IncludeHeaders.empty(); }
64 MATCHER_P(IncludeHeader, P, "") {
65   return (arg.IncludeHeaders.size() == 1) &&
66          (arg.IncludeHeaders.begin()->IncludeHeader == P);
67 }
68 MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") {
69   return (arg.IncludeHeader == IncludeHeader) && (arg.References == References);
70 }
71 MATCHER_P(DeclRange, Pos, "") {
72   return std::make_tuple(arg.CanonicalDeclaration.Start.line(),
73                          arg.CanonicalDeclaration.Start.column(),
74                          arg.CanonicalDeclaration.End.line(),
75                          arg.CanonicalDeclaration.End.column()) ==
76          std::make_tuple(Pos.start.line, Pos.start.character, Pos.end.line,
77                          Pos.end.character);
78 }
79 MATCHER_P(DefRange, Pos, "") {
80   return std::make_tuple(
81              arg.Definition.Start.line(), arg.Definition.Start.column(),
82              arg.Definition.End.line(), arg.Definition.End.column()) ==
83          std::make_tuple(Pos.start.line, Pos.start.character, Pos.end.line,
84                          Pos.end.character);
85 }
86 MATCHER_P(RefCount, R, "") { return int(arg.References) == R; }
87 MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion, "") {
88   return static_cast<bool>(arg.Flags & Symbol::IndexedForCodeCompletion) ==
89          IsIndexedForCodeCompletion;
90 }
91 MATCHER(Deprecated, "") { return arg.Flags & Symbol::Deprecated; }
92 MATCHER(ImplementationDetail, "") {
93   return arg.Flags & Symbol::ImplementationDetail;
94 }
95 MATCHER(VisibleOutsideFile, "") {
96   return static_cast<bool>(arg.Flags & Symbol::VisibleOutsideFile);
97 }
98 MATCHER(RefRange, "") {
99   const Ref &Pos = ::testing::get<0>(arg);
100   const Range &Range = ::testing::get<1>(arg);
101   return std::make_tuple(Pos.Location.Start.line(), Pos.Location.Start.column(),
102                          Pos.Location.End.line(), Pos.Location.End.column()) ==
103          std::make_tuple(Range.start.line, Range.start.character,
104                          Range.end.line, Range.end.character);
105 }
106 ::testing::Matcher<const std::vector<Ref> &>
107 HaveRanges(const std::vector<Range> Ranges) {
108   return ::testing::UnorderedPointwise(RefRange(), Ranges);
109 }
110
111 class ShouldCollectSymbolTest : public ::testing::Test {
112 public:
113   void build(llvm::StringRef HeaderCode, llvm::StringRef Code = "") {
114     File.HeaderFilename = HeaderName;
115     File.Filename = FileName;
116     File.HeaderCode = HeaderCode;
117     File.Code = Code;
118     AST = File.build();
119   }
120
121   // build() must have been called.
122   bool shouldCollect(llvm::StringRef Name, bool Qualified = true) {
123     assert(AST.hasValue());
124     const NamedDecl &ND =
125         Qualified ? findDecl(*AST, Name) : findUnqualifiedDecl(*AST, Name);
126     const SourceManager &SM = AST->getSourceManager();
127     bool MainFile = isInsideMainFile(ND.getBeginLoc(), SM);
128     return SymbolCollector::shouldCollectSymbol(
129         ND, AST->getASTContext(), SymbolCollector::Options(), MainFile);
130   }
131
132 protected:
133   std::string HeaderName = "f.h";
134   std::string FileName = "f.cpp";
135   TestTU File;
136   llvm::Optional<ParsedAST> AST; // Initialized after build.
137 };
138
139 TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
140   build(R"(
141     namespace nx {
142     class X{};
143     auto f() { int Local; } // auto ensures function body is parsed.
144     struct { int x; } var;
145     }
146   )",
147         R"(
148     class InMain {};
149     namespace { class InAnonymous {}; }
150     static void g();
151   )");
152   auto AST = File.build();
153   EXPECT_TRUE(shouldCollect("nx"));
154   EXPECT_TRUE(shouldCollect("nx::X"));
155   EXPECT_TRUE(shouldCollect("nx::f"));
156   EXPECT_TRUE(shouldCollect("InMain"));
157   EXPECT_TRUE(shouldCollect("InAnonymous", /*Qualified=*/false));
158   EXPECT_TRUE(shouldCollect("g"));
159
160   EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false));
161 }
162
163 TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
164   HeaderName = "f.proto.h";
165   build(
166       R"(// Generated by the protocol buffer compiler.  DO NOT EDIT!
167          namespace nx {
168            class Top_Level {};
169            class TopLevel {};
170            enum Kind {
171              KIND_OK,
172              Kind_Not_Ok,
173            };
174          })");
175   EXPECT_TRUE(shouldCollect("nx::TopLevel"));
176   EXPECT_TRUE(shouldCollect("nx::Kind::KIND_OK"));
177   EXPECT_TRUE(shouldCollect("nx::Kind"));
178
179   EXPECT_FALSE(shouldCollect("nx::Top_Level"));
180   EXPECT_FALSE(shouldCollect("nx::Kind::Kind_Not_Ok"));
181 }
182
183 TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
184   HeaderName = "f.proto.h";
185   build(R"(
186     namespace nx {
187       class Top_Level {};
188       enum Kind {
189         Kind_Fine
190       };
191     }
192   )");
193   EXPECT_TRUE(shouldCollect("nx::Top_Level"));
194   EXPECT_TRUE(shouldCollect("nx::Kind_Fine"));
195 }
196
197 class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
198 public:
199   SymbolIndexActionFactory(SymbolCollector::Options COpts,
200                            CommentHandler *PragmaHandler)
201       : COpts(std::move(COpts)), PragmaHandler(PragmaHandler) {}
202
203   std::unique_ptr<FrontendAction> create() override {
204     class IndexAction : public ASTFrontendAction {
205     public:
206       IndexAction(std::shared_ptr<index::IndexDataConsumer> DataConsumer,
207                   const index::IndexingOptions &Opts,
208                   CommentHandler *PragmaHandler)
209           : DataConsumer(std::move(DataConsumer)), Opts(Opts),
210             PragmaHandler(PragmaHandler) {}
211
212       std::unique_ptr<ASTConsumer>
213       CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
214         if (PragmaHandler)
215           CI.getPreprocessor().addCommentHandler(PragmaHandler);
216         return createIndexingASTConsumer(DataConsumer, Opts, CI.getPreprocessorPtr());
217       }
218
219       bool BeginInvocation(CompilerInstance &CI) override {
220         // Make the compiler parse all comments.
221         CI.getLangOpts().CommentOpts.ParseAllComments = true;
222         return true;
223       }
224
225     private:
226       std::shared_ptr<index::IndexDataConsumer> DataConsumer;
227       index::IndexingOptions Opts;
228       CommentHandler *PragmaHandler;
229     };
230     index::IndexingOptions IndexOpts;
231     IndexOpts.SystemSymbolFilter =
232         index::IndexingOptions::SystemSymbolFilterKind::All;
233     IndexOpts.IndexFunctionLocals = false;
234     Collector = std::make_shared<SymbolCollector>(COpts);
235     return std::make_unique<IndexAction>(Collector, std::move(IndexOpts),
236                                          PragmaHandler);
237   }
238
239   std::shared_ptr<SymbolCollector> Collector;
240   SymbolCollector::Options COpts;
241   CommentHandler *PragmaHandler;
242 };
243
244 class SymbolCollectorTest : public ::testing::Test {
245 public:
246   SymbolCollectorTest()
247       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
248         TestHeaderName(testPath("symbol.h")),
249         TestFileName(testPath("symbol.cc")) {
250     TestHeaderURI = URI::create(TestHeaderName).toString();
251     TestFileURI = URI::create(TestFileName).toString();
252   }
253
254   // Note that unlike TestTU, no automatic header guard is added.
255   // HeaderCode should start with #pragma once to be treated as modular.
256   bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode,
257                           const std::vector<std::string> &ExtraArgs = {}) {
258     llvm::IntrusiveRefCntPtr<FileManager> Files(
259         new FileManager(FileSystemOptions(), InMemoryFileSystem));
260
261     auto Factory = std::make_unique<SymbolIndexActionFactory>(
262         CollectorOpts, PragmaHandler.get());
263
264     std::vector<std::string> Args = {"symbol_collector", "-fsyntax-only",
265                                      "-xc++", "-include", TestHeaderName};
266     Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
267     // This allows to override the "-xc++" with something else, i.e.
268     // -xobjective-c++.
269     Args.push_back(TestFileName);
270
271     tooling::ToolInvocation Invocation(
272         Args, Factory->create(), Files.get(),
273         std::make_shared<PCHContainerOperations>());
274
275     InMemoryFileSystem->addFile(TestHeaderName, 0,
276                                 llvm::MemoryBuffer::getMemBuffer(HeaderCode));
277     InMemoryFileSystem->addFile(TestFileName, 0,
278                                 llvm::MemoryBuffer::getMemBuffer(MainCode));
279     Invocation.run();
280     Symbols = Factory->Collector->takeSymbols();
281     Refs = Factory->Collector->takeRefs();
282     Relations = Factory->Collector->takeRelations();
283     return true;
284   }
285
286 protected:
287   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
288   std::string TestHeaderName;
289   std::string TestHeaderURI;
290   std::string TestFileName;
291   std::string TestFileURI;
292   SymbolSlab Symbols;
293   RefSlab Refs;
294   RelationSlab Relations;
295   SymbolCollector::Options CollectorOpts;
296   std::unique_ptr<CommentHandler> PragmaHandler;
297 };
298
299 TEST_F(SymbolCollectorTest, CollectSymbols) {
300   const std::string Header = R"(
301     class Foo {
302       Foo() {}
303       Foo(int a) {}
304       void f();
305       friend void f1();
306       friend class Friend;
307       Foo& operator=(const Foo&);
308       ~Foo();
309       class Nested {
310       void f();
311       };
312     };
313     class Friend {
314     };
315
316     void f1();
317     inline void f2() {}
318     static const int KInt = 2;
319     const char* kStr = "123";
320
321     namespace {
322     void ff() {} // ignore
323     }
324
325     void f1() {}
326
327     namespace foo {
328     // Type alias
329     typedef int int32;
330     using int32_t = int32;
331
332     // Variable
333     int v1;
334
335     // Namespace
336     namespace bar {
337     int v2;
338     }
339     // Namespace alias
340     namespace baz = bar;
341
342     using bar::v2;
343     } // namespace foo
344   )";
345   runSymbolCollector(Header, /*Main=*/"");
346   EXPECT_THAT(Symbols,
347               UnorderedElementsAreArray(
348                   {AllOf(QName("Foo"), ForCodeCompletion(true)),
349                    AllOf(QName("Foo::Foo"), ForCodeCompletion(false)),
350                    AllOf(QName("Foo::Foo"), ForCodeCompletion(false)),
351                    AllOf(QName("Foo::f"), ForCodeCompletion(false)),
352                    AllOf(QName("Foo::~Foo"), ForCodeCompletion(false)),
353                    AllOf(QName("Foo::operator="), ForCodeCompletion(false)),
354                    AllOf(QName("Foo::Nested"), ForCodeCompletion(false)),
355                    AllOf(QName("Foo::Nested::f"), ForCodeCompletion(false)),
356
357                    AllOf(QName("Friend"), ForCodeCompletion(true)),
358                    AllOf(QName("f1"), ForCodeCompletion(true)),
359                    AllOf(QName("f2"), ForCodeCompletion(true)),
360                    AllOf(QName("KInt"), ForCodeCompletion(true)),
361                    AllOf(QName("kStr"), ForCodeCompletion(true)),
362                    AllOf(QName("foo"), ForCodeCompletion(true)),
363                    AllOf(QName("foo::bar"), ForCodeCompletion(true)),
364                    AllOf(QName("foo::int32"), ForCodeCompletion(true)),
365                    AllOf(QName("foo::int32_t"), ForCodeCompletion(true)),
366                    AllOf(QName("foo::v1"), ForCodeCompletion(true)),
367                    AllOf(QName("foo::bar::v2"), ForCodeCompletion(true)),
368                    AllOf(QName("foo::v2"), ForCodeCompletion(true)),
369                    AllOf(QName("foo::baz"), ForCodeCompletion(true))}));
370 }
371
372 TEST_F(SymbolCollectorTest, FileLocal) {
373   const std::string Header = R"(
374     class Foo {};
375     namespace {
376       class Ignored {};
377     }
378     void bar();
379   )";
380   const std::string Main = R"(
381     class ForwardDecl;
382     void bar() {}
383     static void a();
384     class B {};
385     namespace {
386       void c();
387     }
388   )";
389   runSymbolCollector(Header, Main);
390   EXPECT_THAT(Symbols,
391               UnorderedElementsAre(
392                   AllOf(QName("Foo"), VisibleOutsideFile()),
393                   AllOf(QName("bar"), VisibleOutsideFile()),
394                   AllOf(QName("a"), Not(VisibleOutsideFile())),
395                   AllOf(QName("B"), Not(VisibleOutsideFile())),
396                   AllOf(QName("c"), Not(VisibleOutsideFile())),
397                   // FIXME: ForwardDecl likely *is* visible outside.
398                   AllOf(QName("ForwardDecl"), Not(VisibleOutsideFile()))));
399 }
400
401 TEST_F(SymbolCollectorTest, Template) {
402   Annotations Header(R"(
403     // Primary template and explicit specialization are indexed, instantiation
404     // is not.
405     template <class T, class U> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
406     template <> struct $specdecl[[Tmpl]]<int, bool> {};
407     template <class U> struct $partspecdecl[[Tmpl]]<bool, U> {};
408     extern template struct Tmpl<float, bool>;
409     template struct Tmpl<double, bool>;
410   )");
411   runSymbolCollector(Header.code(), /*Main=*/"");
412   EXPECT_THAT(Symbols,
413               UnorderedElementsAre(
414                   AllOf(QName("Tmpl"), DeclRange(Header.range()),
415                         ForCodeCompletion(true)),
416                   AllOf(QName("Tmpl"), DeclRange(Header.range("specdecl")),
417                         ForCodeCompletion(false)),
418                   AllOf(QName("Tmpl"), DeclRange(Header.range("partspecdecl")),
419                         ForCodeCompletion(false)),
420                   AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")),
421                         ForCodeCompletion(false))));
422 }
423
424 TEST_F(SymbolCollectorTest, TemplateArgs) {
425   Annotations Header(R"(
426     template <class X> class $barclasstemp[[Bar]] {};
427     template <class T, class U, template<typename> class Z, int Q>
428     struct [[Tmpl]] { T $xdecl[[x]] = 0; };
429
430     // template-template, non-type and type full spec
431     template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {};
432
433     // template-template, non-type and type partial spec
434     template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {};
435     // instantiation
436     extern template struct Tmpl<float, bool, Bar, 8>;
437     // instantiation
438     template struct Tmpl<double, bool, Bar, 2>;
439
440     template <typename ...> class $fooclasstemp[[Foo]] {};
441     // parameter-packs full spec
442     template<> class $parampack[[Foo]]<Bar<int>, int, double> {};
443     // parameter-packs partial spec
444     template<class T> class $parampackpartial[[Foo]]<T, T> {};
445
446     template <int ...> class $bazclasstemp[[Baz]] {};
447     // non-type parameter-packs full spec
448     template<> class $parampacknontype[[Baz]]<3, 5, 8> {};
449     // non-type parameter-packs partial spec
450     template<int T> class $parampacknontypepartial[[Baz]]<T, T> {};
451
452     template <template <class> class ...> class $fozclasstemp[[Foz]] {};
453     // template-template parameter-packs full spec
454     template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {};
455     // template-template parameter-packs partial spec
456     template<template <class> class T>
457     class $parampacktempltemplpartial[[Foz]]<T, T> {};
458   )");
459   runSymbolCollector(Header.code(), /*Main=*/"");
460   EXPECT_THAT(
461       Symbols,
462       AllOf(
463           Contains(AllOf(QName("Tmpl"), TemplateArgs("<int, bool, Bar, 3>"),
464                          DeclRange(Header.range("specdecl")),
465                          ForCodeCompletion(false))),
466           Contains(AllOf(QName("Tmpl"), TemplateArgs("<bool, U, Bar, T>"),
467                          DeclRange(Header.range("partspecdecl")),
468                          ForCodeCompletion(false))),
469           Contains(AllOf(QName("Foo"), TemplateArgs("<Bar<int>, int, double>"),
470                          DeclRange(Header.range("parampack")),
471                          ForCodeCompletion(false))),
472           Contains(AllOf(QName("Foo"), TemplateArgs("<T, T>"),
473                          DeclRange(Header.range("parampackpartial")),
474                          ForCodeCompletion(false))),
475           Contains(AllOf(QName("Baz"), TemplateArgs("<3, 5, 8>"),
476                          DeclRange(Header.range("parampacknontype")),
477                          ForCodeCompletion(false))),
478           Contains(AllOf(QName("Baz"), TemplateArgs("<T, T>"),
479                          DeclRange(Header.range("parampacknontypepartial")),
480                          ForCodeCompletion(false))),
481           Contains(AllOf(QName("Foz"), TemplateArgs("<Bar, Bar>"),
482                          DeclRange(Header.range("parampacktempltempl")),
483                          ForCodeCompletion(false))),
484           Contains(AllOf(QName("Foz"), TemplateArgs("<T, T>"),
485                          DeclRange(Header.range("parampacktempltemplpartial")),
486                          ForCodeCompletion(false)))));
487 }
488
489 TEST_F(SymbolCollectorTest, ObjCSymbols) {
490   const std::string Header = R"(
491     @interface Person
492     - (void)someMethodName:(void*)name1 lastName:(void*)lName;
493     @end
494
495     @implementation Person
496     - (void)someMethodName:(void*)name1 lastName:(void*)lName{
497       int foo;
498       ^(int param){ int bar; };
499     }
500     @end
501
502     @interface Person (MyCategory)
503     - (void)someMethodName2:(void*)name2;
504     @end
505
506     @implementation Person (MyCategory)
507     - (void)someMethodName2:(void*)name2 {
508       int foo2;
509     }
510     @end
511
512     @protocol MyProtocol
513     - (void)someMethodName3:(void*)name3;
514     @end
515   )";
516   TestFileName = testPath("test.m");
517   runSymbolCollector(Header, /*Main=*/"", {"-fblocks", "-xobjective-c++"});
518   EXPECT_THAT(Symbols,
519               UnorderedElementsAre(
520                   QName("Person"), QName("Person::someMethodName:lastName:"),
521                   QName("MyCategory"), QName("Person::someMethodName2:"),
522                   QName("MyProtocol"), QName("MyProtocol::someMethodName3:")));
523 }
524
525 TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {
526   const std::string Header = R"(
527     @interface Container
528     @property(nonatomic) int magic;
529     @end
530
531     @implementation Container
532     @end
533   )";
534   TestFileName = testPath("test.m");
535   runSymbolCollector(Header, /*Main=*/"", {"-xobjective-c++"});
536   EXPECT_THAT(Symbols, Contains(QName("Container")));
537   EXPECT_THAT(Symbols, Contains(QName("Container::magic")));
538   // FIXME: Results also contain Container::_magic on some platforms.
539   //        Figure out why it's platform-dependent.
540 }
541
542 TEST_F(SymbolCollectorTest, Locations) {
543   Annotations Header(R"cpp(
544     // Declared in header, defined in main.
545     extern int $xdecl[[X]];
546     class $clsdecl[[Cls]];
547     void $printdecl[[print]]();
548
549     // Declared in header, defined nowhere.
550     extern int $zdecl[[Z]];
551
552     void $foodecl[[fo\
553 o]]();
554   )cpp");
555   Annotations Main(R"cpp(
556     int $xdef[[X]] = 42;
557     class $clsdef[[Cls]] {};
558     void $printdef[[print]]() {}
559
560     // Declared/defined in main only.
561     int $ydecl[[Y]];
562   )cpp");
563   runSymbolCollector(Header.code(), Main.code());
564   EXPECT_THAT(Symbols,
565               UnorderedElementsAre(
566                   AllOf(QName("X"), DeclRange(Header.range("xdecl")),
567                         DefRange(Main.range("xdef"))),
568                   AllOf(QName("Cls"), DeclRange(Header.range("clsdecl")),
569                         DefRange(Main.range("clsdef"))),
570                   AllOf(QName("print"), DeclRange(Header.range("printdecl")),
571                         DefRange(Main.range("printdef"))),
572                   AllOf(QName("Z"), DeclRange(Header.range("zdecl"))),
573                   AllOf(QName("foo"), DeclRange(Header.range("foodecl"))),
574                   AllOf(QName("Y"), DeclRange(Main.range("ydecl")))));
575 }
576
577 TEST_F(SymbolCollectorTest, Refs) {
578   Annotations Header(R"(
579   class $foo[[Foo]] {
580   public:
581     $foo[[Foo]]() {}
582     $foo[[Foo]](int);
583   };
584   class $bar[[Bar]];
585   void $func[[func]]();
586
587   namespace $ns[[NS]] {} // namespace ref is ignored
588   )");
589   Annotations Main(R"(
590   class $bar[[Bar]] {};
591
592   void $func[[func]]();
593
594   void fff() {
595     $foo[[Foo]] foo;
596     $bar[[Bar]] bar;
597     $func[[func]]();
598     int abc = 0;
599     $foo[[Foo]] foo2 = abc;
600   }
601   )");
602   Annotations SymbolsOnlyInMainCode(R"(
603   int a;
604   void b() {}
605   static const int c = 0;
606   class d {};
607   )");
608   CollectorOpts.RefFilter = RefKind::All;
609   runSymbolCollector(Header.code(),
610                      (Main.code() + SymbolsOnlyInMainCode.code()).str());
611   auto HeaderSymbols = TestTU::withHeaderCode(Header.code()).headerSymbols();
612
613   EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
614                                   HaveRanges(Main.ranges("foo")))));
615   EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Bar").ID,
616                                   HaveRanges(Main.ranges("bar")))));
617   EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "func").ID,
618                                   HaveRanges(Main.ranges("func")))));
619   EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(Symbols, "NS").ID, _))));
620   // Symbols *only* in the main file (a, b, c) had no refs collected.
621   auto MainSymbols =
622       TestTU::withHeaderCode(SymbolsOnlyInMainCode.code()).headerSymbols();
623   EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "a").ID, _))));
624   EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "b").ID, _))));
625   EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "c").ID, _))));
626 }
627
628
629 TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
630   CollectorOpts.RefFilter = RefKind::All;
631   Annotations Header(R"(
632   class $Foo[[Foo]] {};
633
634   void $Func[[Func]]() {
635     $Foo[[Foo]] fo;
636   }
637   )");
638   // The main file is normal .cpp file, we shouldn't collect any refs of symbols
639   // which are not declared in the preamble.
640   TestFileName = testPath("foo.cpp");
641   runSymbolCollector("", Header.code());
642   EXPECT_THAT(Refs, UnorderedElementsAre());
643
644   // Run the .h file as main file, we should collect the refs.
645   TestFileName = testPath("foo.h");
646   runSymbolCollector("", Header.code(),
647                      /*ExtraArgs=*/{"-xobjective-c++-header"});
648   EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"), QName("Func")));
649   EXPECT_THAT(Refs, UnorderedElementsAre(Pair(findSymbol(Symbols, "Foo").ID,
650                                   HaveRanges(Header.ranges("Foo"))),
651                              Pair(findSymbol(Symbols, "Func").ID,
652                                   HaveRanges(Header.ranges("Func")))));
653 }
654
655 TEST_F(SymbolCollectorTest, RefsInHeaders) {
656   CollectorOpts.RefFilter = RefKind::All;
657   CollectorOpts.RefsInHeaders = true;
658   Annotations Header(R"(
659   class [[Foo]] {};
660   )");
661   runSymbolCollector(Header.code(), "");
662   EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "Foo").ID,
663                                   HaveRanges(Header.ranges()))));
664 }
665
666 TEST_F(SymbolCollectorTest, Relations) {
667   std::string Header = R"(
668   class Base {};
669   class Derived : public Base {};
670   )";
671   runSymbolCollector(Header, /*Main=*/"");
672   const Symbol &Base = findSymbol(Symbols, "Base");
673   const Symbol &Derived = findSymbol(Symbols, "Derived");
674   EXPECT_THAT(Relations,
675               Contains(Relation{Base.ID, index::SymbolRole::RelationBaseOf,
676                                 Derived.ID}));
677 }
678
679 TEST_F(SymbolCollectorTest, References) {
680   const std::string Header = R"(
681     class W;
682     class X {};
683     class Y;
684     class Z {}; // not used anywhere
685     Y* y = nullptr;  // used in header doesn't count
686     #define GLOBAL_Z(name) Z name;
687   )";
688   const std::string Main = R"(
689     W* w = nullptr;
690     W* w2 = nullptr; // only one usage counts
691     X x();
692     class V;
693     class Y{}; // definition doesn't count as a reference
694     V* v = nullptr;
695     GLOBAL_Z(z); // Not a reference to Z, we don't spell the type.
696   )";
697   CollectorOpts.CountReferences = true;
698   runSymbolCollector(Header, Main);
699   EXPECT_THAT(
700       Symbols,
701       UnorderedElementsAreArray(
702           {AllOf(QName("W"), RefCount(1)), AllOf(QName("X"), RefCount(1)),
703            AllOf(QName("Y"), RefCount(0)), AllOf(QName("Z"), RefCount(0)),
704            AllOf(QName("y"), RefCount(0)), AllOf(QName("z"), RefCount(0)),
705            AllOf(QName("x"), RefCount(0)), AllOf(QName("w"), RefCount(0)),
706            AllOf(QName("w2"), RefCount(0)), AllOf(QName("V"), RefCount(1)),
707            AllOf(QName("v"), RefCount(0))}));
708 }
709
710 TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
711   runSymbolCollector("class Foo {};", /*Main=*/"");
712   EXPECT_THAT(Symbols, UnorderedElementsAre(
713                            AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
714 }
715
716 TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
717   TestHeaderName = "x.h";
718   TestFileName = "x.cpp";
719   TestHeaderURI = URI::create(testPath(TestHeaderName)).toString();
720   CollectorOpts.FallbackDir = testRoot();
721   runSymbolCollector("class Foo {};", /*Main=*/"");
722   EXPECT_THAT(Symbols, UnorderedElementsAre(
723                            AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
724 }
725
726 TEST_F(SymbolCollectorTest, UnittestURIScheme) {
727   // Use test URI scheme from URITests.cpp
728   TestHeaderName = testPath("x.h");
729   TestFileName = testPath("x.cpp");
730   runSymbolCollector("class Foo {};", /*Main=*/"");
731   EXPECT_THAT(Symbols, UnorderedElementsAre(
732                            AllOf(QName("Foo"), DeclURI("unittest:///x.h"))));
733 }
734
735 TEST_F(SymbolCollectorTest, IncludeEnums) {
736   const std::string Header = R"(
737     enum {
738       Red
739     };
740     enum Color {
741       Green
742     };
743     enum class Color2 {
744       Yellow
745     };
746     namespace ns {
747     enum {
748       Black
749     };
750     }
751   )";
752   runSymbolCollector(Header, /*Main=*/"");
753   EXPECT_THAT(Symbols,
754               UnorderedElementsAre(
755                   AllOf(QName("Red"), ForCodeCompletion(true)),
756                   AllOf(QName("Color"), ForCodeCompletion(true)),
757                   AllOf(QName("Green"), ForCodeCompletion(true)),
758                   AllOf(QName("Color2"), ForCodeCompletion(true)),
759                   AllOf(QName("Color2::Yellow"), ForCodeCompletion(false)),
760                   AllOf(QName("ns"), ForCodeCompletion(true)),
761                   AllOf(QName("ns::Black"), ForCodeCompletion(true))));
762 }
763
764 TEST_F(SymbolCollectorTest, NamelessSymbols) {
765   const std::string Header = R"(
766     struct {
767       int a;
768     } Foo;
769   )";
770   runSymbolCollector(Header, /*Main=*/"");
771   EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"),
772                                             QName("(anonymous struct)::a")));
773 }
774
775 TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
776
777   Annotations Header(R"(
778     #define FF(name) \
779       class name##_Test {};
780
781     $expansion[[FF]](abc);
782
783     #define FF2() \
784       class $spelling[[Test]] {};
785
786     FF2();
787   )");
788
789   runSymbolCollector(Header.code(), /*Main=*/"");
790   EXPECT_THAT(Symbols,
791               UnorderedElementsAre(
792                   AllOf(QName("abc_Test"), DeclRange(Header.range("expansion")),
793                         DeclURI(TestHeaderURI)),
794                   AllOf(QName("Test"), DeclRange(Header.range("spelling")),
795                         DeclURI(TestHeaderURI))));
796 }
797
798 TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
799   Annotations Header(R"(
800     #ifdef NAME
801     class $expansion[[NAME]] {};
802     #endif
803   )");
804   runSymbolCollector(Header.code(), /*Main=*/"", /*ExtraArgs=*/{"-DNAME=name"});
805   EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
806                            QName("name"), DeclRange(Header.range("expansion")),
807                            DeclURI(TestHeaderURI))));
808 }
809
810 TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
811   const std::string Main = R"(
812     class Foo {};
813     void f1();
814     inline void f2() {}
815
816     namespace {
817     void ff() {}
818     }
819     namespace foo {
820     namespace {
821     class Bar {};
822     }
823     }
824     void main_f() {}
825     void f1() {}
826   )";
827   runSymbolCollector(/*Header=*/"", Main);
828   EXPECT_THAT(Symbols, UnorderedElementsAre(
829                            QName("Foo"), QName("f1"), QName("f2"), QName("ff"),
830                            QName("foo"), QName("foo::Bar"), QName("main_f")));
831 }
832
833 TEST_F(SymbolCollectorTest, Documentation) {
834   const std::string Header = R"(
835     // Doc Foo
836     class Foo {
837       // Doc f
838       int f();
839     };
840   )";
841   CollectorOpts.StoreAllDocumentation = false;
842   runSymbolCollector(Header, /* Main */ "");
843   EXPECT_THAT(Symbols,
844               UnorderedElementsAre(
845                   AllOf(QName("Foo"), Doc("Doc Foo"), ForCodeCompletion(true)),
846                   AllOf(QName("Foo::f"), Doc(""), ReturnType(""),
847                         ForCodeCompletion(false))));
848
849   CollectorOpts.StoreAllDocumentation = true;
850   runSymbolCollector(Header, /* Main */ "");
851   EXPECT_THAT(Symbols,
852               UnorderedElementsAre(
853                   AllOf(QName("Foo"), Doc("Doc Foo"), ForCodeCompletion(true)),
854                   AllOf(QName("Foo::f"), Doc("Doc f"), ReturnType(""),
855                         ForCodeCompletion(false))));
856 }
857
858 TEST_F(SymbolCollectorTest, ClassMembers) {
859   const std::string Header = R"(
860     class Foo {
861       void f() {}
862       void g();
863       static void sf() {}
864       static void ssf();
865       static int x;
866     };
867   )";
868   const std::string Main = R"(
869     void Foo::g() {}
870     void Foo::ssf() {}
871   )";
872   runSymbolCollector(Header, Main);
873   EXPECT_THAT(
874       Symbols,
875       UnorderedElementsAre(
876           QName("Foo"),
877           AllOf(QName("Foo::f"), ReturnType(""), ForCodeCompletion(false)),
878           AllOf(QName("Foo::g"), ReturnType(""), ForCodeCompletion(false)),
879           AllOf(QName("Foo::sf"), ReturnType(""), ForCodeCompletion(false)),
880           AllOf(QName("Foo::ssf"), ReturnType(""), ForCodeCompletion(false)),
881           AllOf(QName("Foo::x"), ReturnType(""), ForCodeCompletion(false))));
882 }
883
884 TEST_F(SymbolCollectorTest, Scopes) {
885   const std::string Header = R"(
886     namespace na {
887     class Foo {};
888     namespace nb {
889     class Bar {};
890     }
891     }
892   )";
893   runSymbolCollector(Header, /*Main=*/"");
894   EXPECT_THAT(Symbols,
895               UnorderedElementsAre(QName("na"), QName("na::nb"),
896                                    QName("na::Foo"), QName("na::nb::Bar")));
897 }
898
899 TEST_F(SymbolCollectorTest, ExternC) {
900   const std::string Header = R"(
901     extern "C" { class Foo {}; }
902     namespace na {
903     extern "C" { class Bar {}; }
904     }
905   )";
906   runSymbolCollector(Header, /*Main=*/"");
907   EXPECT_THAT(Symbols, UnorderedElementsAre(QName("na"), QName("Foo"),
908                                             QName("na::Bar")));
909 }
910
911 TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
912   const std::string Header = R"(
913     namespace na {
914     inline namespace nb {
915     class Foo {};
916     }
917     }
918     namespace na {
919     // This is still inlined.
920     namespace nb {
921     class Bar {};
922     }
923     }
924   )";
925   runSymbolCollector(Header, /*Main=*/"");
926   EXPECT_THAT(Symbols,
927               UnorderedElementsAre(QName("na"), QName("na::nb"),
928                                    QName("na::Foo"), QName("na::Bar")));
929 }
930
931 TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
932   const std::string Header = R"(
933     namespace nx {
934     /// Foo comment.
935     int ff(int x, double y) { return 0; }
936     }
937   )";
938   runSymbolCollector(Header, /*Main=*/"");
939   EXPECT_THAT(
940       Symbols,
941       UnorderedElementsAre(
942           QName("nx"), AllOf(QName("nx::ff"), Labeled("ff(int x, double y)"),
943                              ReturnType("int"), Doc("Foo comment."))));
944 }
945
946 TEST_F(SymbolCollectorTest, Snippet) {
947   const std::string Header = R"(
948     namespace nx {
949     void f() {}
950     int ff(int x, double y) { return 0; }
951     }
952   )";
953   runSymbolCollector(Header, /*Main=*/"");
954   EXPECT_THAT(Symbols,
955               UnorderedElementsAre(
956                   QName("nx"),
957                   AllOf(QName("nx::f"), Labeled("f()"), Snippet("f()")),
958                   AllOf(QName("nx::ff"), Labeled("ff(int x, double y)"),
959                         Snippet("ff(${1:int x}, ${2:double y})"))));
960 }
961
962 TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
963   CollectorOpts.CollectIncludePath = true;
964   runSymbolCollector("#pragma once\nclass Foo {};", /*Main=*/"");
965   EXPECT_THAT(Symbols, UnorderedElementsAre(
966                            AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
967   EXPECT_THAT(Symbols.begin()->IncludeHeaders,
968               UnorderedElementsAre(IncludeHeaderWithRef(TestHeaderURI, 1u)));
969 }
970
971 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
972   CollectorOpts.CollectIncludePath = true;
973   CanonicalIncludes Includes;
974   auto Language = LangOptions();
975   Language.CPlusPlus = true;
976   addSystemHeadersMapping(&Includes, Language);
977   CollectorOpts.Includes = &Includes;
978   runSymbolCollector("namespace std { class string {}; }", /*Main=*/"");
979   EXPECT_THAT(Symbols,
980               Contains(AllOf(QName("std::string"), DeclURI(TestHeaderURI),
981                              IncludeHeader("<string>"))));
982 }
983
984 TEST_F(SymbolCollectorTest, IWYUPragma) {
985   CollectorOpts.CollectIncludePath = true;
986   CanonicalIncludes Includes;
987   PragmaHandler = collectIWYUHeaderMaps(&Includes);
988   CollectorOpts.Includes = &Includes;
989   const std::string Header = R"(
990     // IWYU pragma: private, include the/good/header.h
991     class Foo {};
992   )";
993   runSymbolCollector(Header, /*Main=*/"");
994   EXPECT_THAT(Symbols, UnorderedElementsAre(
995                            AllOf(QName("Foo"), DeclURI(TestHeaderURI),
996                                  IncludeHeader("\"the/good/header.h\""))));
997 }
998
999 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1000   CollectorOpts.CollectIncludePath = true;
1001   CanonicalIncludes Includes;
1002   PragmaHandler = collectIWYUHeaderMaps(&Includes);
1003   CollectorOpts.Includes = &Includes;
1004   const std::string Header = R"(
1005     // IWYU pragma: private, include "the/good/header.h"
1006     class Foo {};
1007   )";
1008   runSymbolCollector(Header, /*Main=*/"");
1009   EXPECT_THAT(Symbols, UnorderedElementsAre(
1010                            AllOf(QName("Foo"), DeclURI(TestHeaderURI),
1011                                  IncludeHeader("\"the/good/header.h\""))));
1012 }
1013
1014 TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
1015   CollectorOpts.CollectIncludePath = true;
1016   CanonicalIncludes Includes;
1017   Includes.addMapping(TestHeaderName, "<canonical>");
1018   CollectorOpts.Includes = &Includes;
1019   auto IncFile = testPath("test.inc");
1020   auto IncURI = URI::create(IncFile).toString();
1021   InMemoryFileSystem->addFile(IncFile, 0,
1022                               llvm::MemoryBuffer::getMemBuffer("class X {};"));
1023   runSymbolCollector("#include \"test.inc\"\nclass Y {};", /*Main=*/"",
1024                      /*ExtraArgs=*/{"-I", testRoot()});
1025   EXPECT_THAT(Symbols,
1026               UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
1027                                          IncludeHeader("<canonical>")),
1028                                    AllOf(QName("Y"), DeclURI(TestHeaderURI),
1029                                          IncludeHeader("<canonical>"))));
1030 }
1031
1032 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1033   CollectorOpts.CollectIncludePath = true;
1034   // To make this case as hard as possible, we won't tell clang main is a
1035   // header. No extension, no -x c++-header.
1036   TestFileName = testPath("no_ext_main");
1037   TestFileURI = URI::create(TestFileName).toString();
1038   auto IncFile = testPath("test.inc");
1039   auto IncURI = URI::create(IncFile).toString();
1040   InMemoryFileSystem->addFile(IncFile, 0,
1041                               llvm::MemoryBuffer::getMemBuffer("class X {};"));
1042   runSymbolCollector("", R"cpp(
1043     // Can't use #pragma once in a main file clang doesn't think is a header.
1044     #ifndef MAIN_H_
1045     #define MAIN_H_
1046     #include "test.inc"
1047     #endif
1048   )cpp",
1049                      /*ExtraArgs=*/{"-I", testRoot()});
1050   EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
1051                                                   IncludeHeader(TestFileURI))));
1052 }
1053
1054 TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1055   CollectorOpts.CollectIncludePath = true;
1056   TestFileName = testPath("main.cc");
1057   TestFileURI = URI::create(TestFileName).toString();
1058   auto IncFile = testPath("test.inc");
1059   auto IncURI = URI::create(IncFile).toString();
1060   InMemoryFileSystem->addFile(IncFile, 0,
1061                               llvm::MemoryBuffer::getMemBuffer("class X {};"));
1062   runSymbolCollector("", R"cpp(
1063     #include "test.inc"
1064   )cpp",
1065                      /*ExtraArgs=*/{"-I", testRoot()});
1066   EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
1067                                                   Not(IncludeHeader()))));
1068 }
1069
1070 // Features that depend on header-guards are fragile. Header guards are only
1071 // recognized when the file ends, so we have to defer checking for them.
1072 TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1073   CollectorOpts.CollectIncludePath = true;
1074   CollectorOpts.CollectMacro = true;
1075   runSymbolCollector(R"cpp(
1076     #ifndef HEADER_GUARD_
1077     #define HEADER_GUARD_
1078
1079     // Symbols are seen before the header guard is complete.
1080     #define MACRO
1081     int decl();
1082
1083     #endif // Header guard is recognized here.
1084   )cpp",
1085                      "");
1086   EXPECT_THAT(Symbols, Not(Contains(QName("HEADER_GUARD_"))));
1087   EXPECT_THAT(Symbols, Each(IncludeHeader()));
1088 }
1089
1090 TEST_F(SymbolCollectorTest, NonModularHeader) {
1091   auto TU = TestTU::withHeaderCode("int x();");
1092   EXPECT_THAT(TU.headerSymbols(), ElementsAre(IncludeHeader()));
1093
1094   // Files missing include guards aren't eligible for insertion.
1095   TU.ImplicitHeaderGuard = false;
1096   EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(IncludeHeader())));
1097
1098   // We recognize some patterns of trying to prevent insertion.
1099   TU = TestTU::withHeaderCode(R"cpp(
1100 #ifndef SECRET
1101 #error "This file isn't safe to include directly"
1102 #endif
1103     int x();
1104     )cpp");
1105   TU.ExtraArgs.push_back("-DSECRET"); // *we're* able to include it.
1106   EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(IncludeHeader())));
1107 }
1108
1109 TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1110   CollectorOpts.CollectIncludePath = true;
1111   Annotations Header(R"(
1112     #pragma once
1113     // Forward declarations of TagDecls.
1114     class C;
1115     struct S;
1116     union U;
1117
1118     // Canonical declarations.
1119     class $cdecl[[C]] {};
1120     struct $sdecl[[S]] {};
1121     union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
1122   )");
1123   runSymbolCollector(Header.code(), /*Main=*/"");
1124   EXPECT_THAT(
1125       Symbols,
1126       UnorderedElementsAre(
1127           AllOf(QName("C"), DeclURI(TestHeaderURI),
1128                 DeclRange(Header.range("cdecl")), IncludeHeader(TestHeaderURI),
1129                 DefURI(TestHeaderURI), DefRange(Header.range("cdecl"))),
1130           AllOf(QName("S"), DeclURI(TestHeaderURI),
1131                 DeclRange(Header.range("sdecl")), IncludeHeader(TestHeaderURI),
1132                 DefURI(TestHeaderURI), DefRange(Header.range("sdecl"))),
1133           AllOf(QName("U"), DeclURI(TestHeaderURI),
1134                 DeclRange(Header.range("udecl")), IncludeHeader(TestHeaderURI),
1135                 DefURI(TestHeaderURI), DefRange(Header.range("udecl"))),
1136           AllOf(QName("U::x"), DeclURI(TestHeaderURI),
1137                 DeclRange(Header.range("xdecl")), DefURI(TestHeaderURI),
1138                 DefRange(Header.range("xdecl"))),
1139           AllOf(QName("U::y"), DeclURI(TestHeaderURI),
1140                 DeclRange(Header.range("ydecl")), DefURI(TestHeaderURI),
1141                 DefRange(Header.range("ydecl")))));
1142 }
1143
1144 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1145   CollectorOpts.CollectIncludePath = true;
1146   runSymbolCollector(/*Header=*/"#pragma once\nclass X;",
1147                      /*Main=*/"class X {};");
1148   EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
1149                            QName("X"), DeclURI(TestHeaderURI),
1150                            IncludeHeader(TestHeaderURI), DefURI(TestFileURI))));
1151 }
1152
1153 TEST_F(SymbolCollectorTest, UTF16Character) {
1154   // ö is 2-bytes.
1155   Annotations Header(/*Header=*/"class [[pörk]] {};");
1156   runSymbolCollector(Header.code(), /*Main=*/"");
1157   EXPECT_THAT(Symbols, UnorderedElementsAre(
1158                            AllOf(QName("pörk"), DeclRange(Header.range()))));
1159 }
1160
1161 TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1162   Annotations Header(R"(
1163     namespace nx {
1164       class $z[[Z]] {};
1165       class X {
1166         friend class Y;
1167         friend class Z;
1168         friend void foo();
1169         friend void $bar[[bar]]() {}
1170       };
1171       class $y[[Y]] {};
1172       void $foo[[foo]]();
1173     }
1174   )");
1175   runSymbolCollector(Header.code(), /*Main=*/"");
1176
1177   EXPECT_THAT(Symbols,
1178               UnorderedElementsAre(
1179                   QName("nx"), QName("nx::X"),
1180                   AllOf(QName("nx::Y"), DeclRange(Header.range("y"))),
1181                   AllOf(QName("nx::Z"), DeclRange(Header.range("z"))),
1182                   AllOf(QName("nx::foo"), DeclRange(Header.range("foo"))),
1183                   AllOf(QName("nx::bar"), DeclRange(Header.range("bar")))));
1184 }
1185
1186 TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1187   const std::string Header = R"(
1188     class X;
1189     class Y;
1190   )";
1191   const std::string Main = R"(
1192     class C {
1193       friend ::X;
1194       friend class Y;
1195     };
1196   )";
1197   CollectorOpts.CountReferences = true;
1198   runSymbolCollector(Header, Main);
1199   EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), RefCount(1)),
1200                                             AllOf(QName("Y"), RefCount(1)),
1201                                             AllOf(QName("C"), RefCount(0))));
1202 }
1203
1204 TEST_F(SymbolCollectorTest, Origin) {
1205   CollectorOpts.Origin = SymbolOrigin::Static;
1206   runSymbolCollector("class Foo {};", /*Main=*/"");
1207   EXPECT_THAT(Symbols, UnorderedElementsAre(
1208                            Field(&Symbol::Origin, SymbolOrigin::Static)));
1209 }
1210
1211 TEST_F(SymbolCollectorTest, CollectMacros) {
1212   CollectorOpts.CollectIncludePath = true;
1213   Annotations Header(R"(
1214     #pragma once
1215     #define X 1
1216     #define $mac[[MAC]](x) int x
1217     #define $used[[USED]](y) float y;
1218
1219     MAC(p);
1220   )");
1221
1222   Annotations Main(R"(
1223     #define $main[[MAIN]] 1
1224      USED(t);
1225   )");
1226   CollectorOpts.CountReferences = true;
1227   CollectorOpts.CollectMacro = true;
1228   runSymbolCollector(Header.code(), Main.code());
1229   EXPECT_THAT(
1230       Symbols,
1231       UnorderedElementsAre(
1232           QName("p"), QName("t"),
1233           AllOf(QName("X"), DeclURI(TestHeaderURI),
1234                 IncludeHeader(TestHeaderURI)),
1235           AllOf(Labeled("MAC(x)"), RefCount(0),
1236
1237                 DeclRange(Header.range("mac")), VisibleOutsideFile()),
1238           AllOf(Labeled("USED(y)"), RefCount(1),
1239                 DeclRange(Header.range("used")), VisibleOutsideFile()),
1240           AllOf(Labeled("MAIN"), RefCount(0), DeclRange(Main.range("main")),
1241                 Not(VisibleOutsideFile()))));
1242 }
1243
1244 TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1245   const std::string Header = R"(
1246     void TestClangc() __attribute__((deprecated("", "")));
1247     void TestClangd();
1248   )";
1249   runSymbolCollector(Header, /**/ "");
1250   EXPECT_THAT(Symbols, UnorderedElementsAre(
1251                            AllOf(QName("TestClangc"), Deprecated()),
1252                            AllOf(QName("TestClangd"), Not(Deprecated()))));
1253 }
1254
1255 TEST_F(SymbolCollectorTest, ImplementationDetail) {
1256   const std::string Header = R"(
1257     #define DECL_NAME(x, y) x##_##y##_Decl
1258     #define DECL(x, y) class DECL_NAME(x, y) {};
1259     DECL(X, Y); // X_Y_Decl
1260
1261     class Public {};
1262   )";
1263   runSymbolCollector(Header, /**/ "");
1264   EXPECT_THAT(Symbols,
1265               UnorderedElementsAre(
1266                   AllOf(QName("X_Y_Decl"), ImplementationDetail()),
1267                   AllOf(QName("Public"), Not(ImplementationDetail()))));
1268 }
1269
1270 TEST_F(SymbolCollectorTest, UsingDecl) {
1271   const char *Header = R"(
1272   void foo();
1273   namespace std {
1274     using ::foo;
1275   })";
1276   runSymbolCollector(Header, /**/ "");
1277   EXPECT_THAT(Symbols, Contains(QName("std::foo")));
1278 }
1279
1280 TEST_F(SymbolCollectorTest, CBuiltins) {
1281   // In C, printf in stdio.h is a redecl of an implicit builtin.
1282   const char *Header = R"(
1283     extern int printf(const char*, ...);
1284   )";
1285   runSymbolCollector(Header, /**/ "", {"-xc"});
1286   EXPECT_THAT(Symbols, Contains(QName("printf")));
1287 }
1288
1289 TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1290   const char *Header = R"(
1291       void operator delete(void*)
1292         __attribute__((__externally_visible__));)";
1293   runSymbolCollector(Header, /**/ "");
1294   EXPECT_THAT(Symbols, Contains(QName("operator delete")));
1295 }
1296
1297 } // namespace
1298 } // namespace clangd
1299 } // namespace clang