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