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