1 //===-- FindAllSymbolsTests.cpp - find all symbols unit tests ---*- 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 "FindAllSymbolsAction.h"
10 #include "HeaderMapCollector.h"
11 #include "SymbolInfo.h"
12 #include "SymbolReporter.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/Basic/FileManager.h"
15 #include "clang/Basic/FileSystemOptions.h"
16 #include "clang/Frontend/CompilerInstance.h"
17 #include "clang/Frontend/PCHContainerOperations.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/VirtualFileSystem.h"
24 #include "gtest/gtest.h"
25 #include <memory>
26 #include <string>
27 #include <vector>
28 
29 namespace clang {
30 namespace find_all_symbols {
31 
32 static const char HeaderName[] = "symbols.h";
33 
34 class TestSymbolReporter : public SymbolReporter {
35 public:
~TestSymbolReporter()36   ~TestSymbolReporter() override {}
37 
reportSymbols(llvm::StringRef FileName,const SymbolInfo::SignalMap & NewSymbols)38   void reportSymbols(llvm::StringRef FileName,
39                      const SymbolInfo::SignalMap &NewSymbols) override {
40     for (const auto &Entry : NewSymbols)
41       Symbols[Entry.first] += Entry.second;
42   }
43 
seen(const SymbolInfo & Symbol) const44   int seen(const SymbolInfo &Symbol) const {
45     auto it = Symbols.find(Symbol);
46     return it == Symbols.end() ? 0 : it->second.Seen;
47   }
48 
used(const SymbolInfo & Symbol) const49   int used(const SymbolInfo &Symbol) const {
50     auto it = Symbols.find(Symbol);
51     return it == Symbols.end() ? 0 : it->second.Used;
52   }
53 
54 private:
55   SymbolInfo::SignalMap Symbols;
56 };
57 
58 class FindAllSymbolsTest : public ::testing::Test {
59 public:
seen(const SymbolInfo & Symbol)60   int seen(const SymbolInfo &Symbol) { return Reporter.seen(Symbol); }
61 
used(const SymbolInfo & Symbol)62   int used(const SymbolInfo &Symbol) { return Reporter.used(Symbol); }
63 
runFindAllSymbols(StringRef HeaderCode,StringRef MainCode)64   bool runFindAllSymbols(StringRef HeaderCode, StringRef MainCode) {
65     llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
66         new llvm::vfs::InMemoryFileSystem);
67     llvm::IntrusiveRefCntPtr<FileManager> Files(
68         new FileManager(FileSystemOptions(), InMemoryFileSystem));
69 
70     std::string FileName = "symbol.cc";
71 
72     const std::string InternalHeader = "internal/internal_header.h";
73     const std::string TopHeader = "<top>";
74     // Test .inc header path. The header for `IncHeaderClass` should be
75     // internal.h, which will eventually be mapped to <top>.
76     std::string IncHeader = "internal/private.inc";
77     std::string IncHeaderCode = "class IncHeaderClass {};";
78 
79     HeaderMapCollector::RegexHeaderMap RegexMap = {
80         {R"(internal_.*\.h$)", TopHeader.c_str()},
81     };
82 
83     std::string InternalCode =
84         "#include \"private.inc\"\nclass Internal {};";
85     SymbolInfo InternalSymbol("Internal", SymbolInfo::SymbolKind::Class,
86                               TopHeader, {});
87     SymbolInfo IncSymbol("IncHeaderClass", SymbolInfo::SymbolKind::Class,
88                          TopHeader, {});
89     InMemoryFileSystem->addFile(
90         IncHeader, 0, llvm::MemoryBuffer::getMemBuffer(IncHeaderCode));
91     InMemoryFileSystem->addFile(InternalHeader, 0,
92                                 llvm::MemoryBuffer::getMemBuffer(InternalCode));
93 
94     std::unique_ptr<tooling::FrontendActionFactory> Factory(
95         new FindAllSymbolsActionFactory(&Reporter, &RegexMap));
96 
97     tooling::ToolInvocation Invocation(
98         {std::string("find_all_symbols"), std::string("-fsyntax-only"),
99          std::string("-std=c++11"), FileName},
100         Factory->create(), Files.get(),
101         std::make_shared<PCHContainerOperations>());
102 
103     InMemoryFileSystem->addFile(HeaderName, 0,
104                                 llvm::MemoryBuffer::getMemBuffer(HeaderCode));
105 
106     std::string Content = "#include\"" + std::string(HeaderName) +
107                           "\"\n"
108                           "#include \"" +
109                           InternalHeader + "\"";
110 #if !defined(_MSC_VER) && !defined(__MINGW32__)
111     // Test path cleaning for both decls and macros.
112     const std::string DirtyHeader = "./internal/./a/b.h";
113     Content += "\n#include \"" + DirtyHeader + "\"";
114     const std::string CleanHeader = "internal/a/b.h";
115     const std::string DirtyHeaderContent =
116         "#define INTERNAL 1\nclass ExtraInternal {};";
117     InMemoryFileSystem->addFile(
118         DirtyHeader, 0, llvm::MemoryBuffer::getMemBuffer(DirtyHeaderContent));
119     SymbolInfo DirtyMacro("INTERNAL", SymbolInfo::SymbolKind::Macro,
120                           CleanHeader, {});
121     SymbolInfo DirtySymbol("ExtraInternal", SymbolInfo::SymbolKind::Class,
122                            CleanHeader, {});
123 #endif // _MSC_VER && __MINGW32__
124     Content += "\n" + MainCode.str();
125     InMemoryFileSystem->addFile(FileName, 0,
126                                 llvm::MemoryBuffer::getMemBuffer(Content));
127     Invocation.run();
128     EXPECT_EQ(1, seen(InternalSymbol));
129     EXPECT_EQ(1, seen(IncSymbol));
130 #if !defined(_MSC_VER) && !defined(__MINGW32__)
131     EXPECT_EQ(1, seen(DirtySymbol));
132     EXPECT_EQ(1, seen(DirtyMacro));
133 #endif  // _MSC_VER && __MINGW32__
134     return true;
135   }
136 
137 protected:
138   TestSymbolReporter Reporter;
139 };
140 
TEST_F(FindAllSymbolsTest,VariableSymbols)141 TEST_F(FindAllSymbolsTest, VariableSymbols) {
142   static const char Header[] = R"(
143       extern int xargc;
144       namespace na {
145       static bool SSSS = false;
146       namespace nb { const long long *XXXX; }
147       })";
148   static const char Main[] = R"(
149       auto y = &na::nb::XXXX;
150       int main() { if (na::SSSS) return xargc; }
151   )";
152   runFindAllSymbols(Header, Main);
153 
154   SymbolInfo Symbol =
155       SymbolInfo("xargc", SymbolInfo::SymbolKind::Variable, HeaderName, {});
156   EXPECT_EQ(1, seen(Symbol));
157   EXPECT_EQ(1, used(Symbol));
158 
159   Symbol = SymbolInfo("SSSS", SymbolInfo::SymbolKind::Variable, HeaderName,
160                       {{SymbolInfo::ContextType::Namespace, "na"}});
161   EXPECT_EQ(1, seen(Symbol));
162   EXPECT_EQ(1, used(Symbol));
163 
164   Symbol = SymbolInfo("XXXX", SymbolInfo::SymbolKind::Variable, HeaderName,
165                       {{SymbolInfo::ContextType::Namespace, "nb"},
166                        {SymbolInfo::ContextType::Namespace, "na"}});
167   EXPECT_EQ(1, seen(Symbol));
168   EXPECT_EQ(1, used(Symbol));
169 }
170 
TEST_F(FindAllSymbolsTest,ExternCSymbols)171 TEST_F(FindAllSymbolsTest, ExternCSymbols) {
172   static const char Header[] = R"(
173       extern "C" {
174       int C_Func() { return 0; }
175       struct C_struct {
176         int Member;
177       };
178       })";
179   static const char Main[] = R"(
180       C_struct q() {
181         int(*ptr)() = C_Func;
182         return {0};
183       }
184   )";
185   runFindAllSymbols(Header, Main);
186 
187   SymbolInfo Symbol =
188       SymbolInfo("C_Func", SymbolInfo::SymbolKind::Function, HeaderName, {});
189   EXPECT_EQ(1, seen(Symbol));
190   EXPECT_EQ(1, used(Symbol));
191 
192   Symbol =
193       SymbolInfo("C_struct", SymbolInfo::SymbolKind::Class, HeaderName, {});
194   EXPECT_EQ(1, seen(Symbol));
195   EXPECT_EQ(1, used(Symbol));
196 }
197 
TEST_F(FindAllSymbolsTest,CXXRecordSymbols)198 TEST_F(FindAllSymbolsTest, CXXRecordSymbols) {
199   static const char Header[] = R"(
200       struct Glob {};
201       struct A; // Not a definition, ignored.
202       class NOP; // Not a definition, ignored
203       namespace na {
204       struct A {
205         struct AAAA {};
206         int x;
207         int y;
208         void f() {}
209       };
210       };  //
211       )";
212   static const char Main[] = R"(
213       static Glob glob;
214       static na::A::AAAA* a;
215   )";
216   runFindAllSymbols(Header, Main);
217 
218   SymbolInfo Symbol =
219       SymbolInfo("Glob", SymbolInfo::SymbolKind::Class, HeaderName, {});
220   EXPECT_EQ(1, seen(Symbol));
221   EXPECT_EQ(1, used(Symbol));
222 
223   Symbol = SymbolInfo("A", SymbolInfo::SymbolKind::Class, HeaderName,
224                       {{SymbolInfo::ContextType::Namespace, "na"}});
225   EXPECT_EQ(1, seen(Symbol));
226   EXPECT_EQ(1, used(Symbol));
227 
228   Symbol = SymbolInfo("AAA", SymbolInfo::SymbolKind::Class, HeaderName,
229                       {{SymbolInfo::ContextType::Record, "A"},
230                        {SymbolInfo::ContextType::Namespace, "na"}});
231   EXPECT_EQ(0, seen(Symbol));
232   EXPECT_EQ(0, used(Symbol));
233 }
234 
TEST_F(FindAllSymbolsTest,CXXRecordSymbolsTemplate)235 TEST_F(FindAllSymbolsTest, CXXRecordSymbolsTemplate) {
236   static const char Header[] = R"(
237       template <typename T>
238       struct T_TEMP {
239         template <typename _Tp1>
240         struct rebind { typedef T_TEMP<_Tp1> other; };
241       };
242       // Ignore specialization.
243       template class T_TEMP<char>;
244 
245       template <typename T>
246       class Observer {
247       };
248       // Ignore specialization.
249       template <> class Observer<int> {};
250       )";
251   static const char Main[] = R"(
252       extern T_TEMP<int>::rebind<char> weirdo;
253   )";
254   runFindAllSymbols(Header, Main);
255 
256   SymbolInfo Symbol =
257       SymbolInfo("T_TEMP", SymbolInfo::SymbolKind::Class, HeaderName, {});
258   EXPECT_EQ(1, seen(Symbol));
259   EXPECT_EQ(1, used(Symbol));
260 }
261 
TEST_F(FindAllSymbolsTest,DontIgnoreTemplatePartialSpecialization)262 TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {
263   static const char Code[] = R"(
264       template<class> class Class; // undefined
265       template<class R, class... ArgTypes>
266       class Class<R(ArgTypes...)> {
267       };
268 
269       template<class T> void f() {};
270       template<> void f<int>() {};
271       )";
272   runFindAllSymbols(Code, "");
273   SymbolInfo Symbol =
274       SymbolInfo("Class", SymbolInfo::SymbolKind::Class, HeaderName, {});
275   EXPECT_EQ(1, seen(Symbol));
276   Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName, {});
277   EXPECT_EQ(1, seen(Symbol));
278 }
279 
TEST_F(FindAllSymbolsTest,FunctionSymbols)280 TEST_F(FindAllSymbolsTest, FunctionSymbols) {
281   static const char Header[] = R"(
282       namespace na {
283       int gg(int);
284       int f(const int &a) { int Local; static int StaticLocal; return 0; }
285       static void SSSFFF() {}
286       }  // namespace na
287       namespace na {
288       namespace nb {
289       template<typename T>
290       void fun(T t) {};
291       } // namespace nb
292       } // namespace na";
293       )";
294   static const char Main[] = R"(
295       int(*gg)(int) = &na::gg;
296       int main() {
297         (void)na::SSSFFF;
298         na::nb::fun(0);
299         return na::f(gg(0));
300       }
301   )";
302   runFindAllSymbols(Header, Main);
303 
304   SymbolInfo Symbol =
305       SymbolInfo("gg", SymbolInfo::SymbolKind::Function, HeaderName,
306                  {{SymbolInfo::ContextType::Namespace, "na"}});
307   EXPECT_EQ(1, seen(Symbol));
308   EXPECT_EQ(1, used(Symbol));
309 
310   Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName,
311                       {{SymbolInfo::ContextType::Namespace, "na"}});
312   EXPECT_EQ(1, seen(Symbol));
313   EXPECT_EQ(1, used(Symbol));
314 
315   Symbol = SymbolInfo("SSSFFF", SymbolInfo::SymbolKind::Function, HeaderName,
316                       {{SymbolInfo::ContextType::Namespace, "na"}});
317   EXPECT_EQ(1, seen(Symbol));
318   EXPECT_EQ(1, used(Symbol));
319 
320   Symbol = SymbolInfo("fun", SymbolInfo::SymbolKind::Function, HeaderName,
321                       {{SymbolInfo::ContextType::Namespace, "nb"},
322                        {SymbolInfo::ContextType::Namespace, "na"}});
323   EXPECT_EQ(1, seen(Symbol));
324   EXPECT_EQ(1, used(Symbol));
325 }
326 
327 TEST_F(FindAllSymbolsTest, NamespaceTest) {
328   static const char Header[] = R"(
329       int X1;
330       namespace { int X2; }
331       namespace { namespace { int X3; } }
332       namespace { namespace nb { int X4; } }
333       namespace na { inline namespace __1 { int X5; } }
334       )";
335   static const char Main[] = R"(
336       using namespace nb;
337       int main() {
338         X1 = X2;
339         X3 = X4;
340         (void)na::X5;
341       }
342   )";
343   runFindAllSymbols(Header, Main);
344 
345   SymbolInfo Symbol =
346       SymbolInfo("X1", SymbolInfo::SymbolKind::Variable, HeaderName, {});
347   EXPECT_EQ(1, seen(Symbol));
348   EXPECT_EQ(1, used(Symbol));
349 
350   Symbol = SymbolInfo("X2", SymbolInfo::SymbolKind::Variable, HeaderName,
351                       {{SymbolInfo::ContextType::Namespace, ""}});
352   EXPECT_EQ(1, seen(Symbol));
353   EXPECT_EQ(1, used(Symbol));
354 
355   Symbol = SymbolInfo("X3", SymbolInfo::SymbolKind::Variable, HeaderName,
356                       {{SymbolInfo::ContextType::Namespace, ""},
357                        {SymbolInfo::ContextType::Namespace, ""}});
358   EXPECT_EQ(1, seen(Symbol));
359   EXPECT_EQ(1, used(Symbol));
360 
361   Symbol = SymbolInfo("X4", SymbolInfo::SymbolKind::Variable, HeaderName,
362                       {{SymbolInfo::ContextType::Namespace, "nb"},
363                        {SymbolInfo::ContextType::Namespace, ""}});
364   EXPECT_EQ(1, seen(Symbol));
365   EXPECT_EQ(1, used(Symbol));
366 
367   Symbol = SymbolInfo("X5", SymbolInfo::SymbolKind::Variable, HeaderName,
368                       {{SymbolInfo::ContextType::Namespace, "na"}});
369   EXPECT_EQ(1, seen(Symbol));
370   EXPECT_EQ(1, used(Symbol));
371 }
372 
373 TEST_F(FindAllSymbolsTest, DecayedTypeTest) {
374   static const char Header[] = "void DecayedFunc(int x[], int y[10]) {}";
375   static const char Main[] = R"(int main() { DecayedFunc(nullptr, nullptr); })";
376   runFindAllSymbols(Header, Main);
377   SymbolInfo Symbol = SymbolInfo(
378       "DecayedFunc", SymbolInfo::SymbolKind::Function, HeaderName, {});
379   EXPECT_EQ(1, seen(Symbol));
380   EXPECT_EQ(1, used(Symbol));
381 }
382 
383 TEST_F(FindAllSymbolsTest, CTypedefTest) {
384   static const char Header[] = R"(
385       typedef unsigned size_t_;
386       typedef struct { int x; } X;
387       using XX = X;
388       )";
389   static const char Main[] = R"(
390       size_t_ f;
391       template<typename T> struct vector{};
392       vector<X> list;
393       void foo(const XX&){}
394   )";
395   runFindAllSymbols(Header, Main);
396 
397   SymbolInfo Symbol = SymbolInfo("size_t_", SymbolInfo::SymbolKind::TypedefName,
398                                  HeaderName, {});
399   EXPECT_EQ(1, seen(Symbol));
400   EXPECT_EQ(1, used(Symbol));
401 
402   Symbol = SymbolInfo("X", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});
403   EXPECT_EQ(1, seen(Symbol));
404   EXPECT_EQ(1, used(Symbol));
405 
406   Symbol =
407       SymbolInfo("XX", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});
408   EXPECT_EQ(1, seen(Symbol));
409   EXPECT_EQ(1, used(Symbol));
410 }
411 
412 TEST_F(FindAllSymbolsTest, EnumTest) {
413   static const char Header[] = R"(
414       enum Glob_E { G1, G2 };
415       enum class Altitude { high='h', low='l'};
416       enum { A1, A2 };
417       class A {
418       public:
419         enum A_ENUM { X1, X2 };
420       };
421       enum DECL : int;
422       )";
423   static const char Main[] = R"(
424       static auto flags = G1 | G2;
425       static auto alt = Altitude::high;
426       static auto nested = A::X1;
427       extern DECL whatever;
428       static auto flags2 = A1 | A2;
429   )";
430   runFindAllSymbols(Header, Main);
431 
432   SymbolInfo Symbol =
433       SymbolInfo("Glob_E", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
434   EXPECT_EQ(1, seen(Symbol));
435   EXPECT_EQ(0, used(Symbol));
436 
437   Symbol =
438       SymbolInfo("G1", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
439                  {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
440   EXPECT_EQ(1, seen(Symbol));
441   EXPECT_EQ(1, used(Symbol));
442 
443   Symbol =
444       SymbolInfo("G2", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
445                  {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
446   EXPECT_EQ(1, seen(Symbol));
447   EXPECT_EQ(1, used(Symbol));
448 
449   Symbol =
450       SymbolInfo("Altitude", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
451   EXPECT_EQ(1, seen(Symbol));
452   EXPECT_EQ(1, used(Symbol));
453   Symbol =
454       SymbolInfo("high", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
455                  {{SymbolInfo::ContextType::EnumDecl, "Altitude"}});
456   EXPECT_EQ(0, seen(Symbol));
457   EXPECT_EQ(0, used(Symbol));
458 
459   Symbol = SymbolInfo("A1", SymbolInfo::SymbolKind::EnumConstantDecl,
460                       HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});
461   EXPECT_EQ(1, seen(Symbol));
462   EXPECT_EQ(1, used(Symbol));
463   Symbol = SymbolInfo("A2", SymbolInfo::SymbolKind::EnumConstantDecl,
464                       HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});
465   EXPECT_EQ(1, seen(Symbol));
466   EXPECT_EQ(1, used(Symbol));
467   Symbol = SymbolInfo("", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
468   EXPECT_EQ(0, seen(Symbol));
469   EXPECT_EQ(0, used(Symbol));
470 
471   Symbol = SymbolInfo("A_ENUM", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
472                       {{SymbolInfo::ContextType::Record, "A"}});
473   EXPECT_EQ(0, seen(Symbol));
474   EXPECT_EQ(0, used(Symbol));
475 
476   Symbol = SymbolInfo("X1", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
477                       {{SymbolInfo::ContextType::EnumDecl, "A_ENUM"},
478                        {SymbolInfo::ContextType::Record, "A"}});
479   EXPECT_EQ(0, seen(Symbol));
480 
481   Symbol = SymbolInfo("DECL", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
482   EXPECT_EQ(0, seen(Symbol));
483 }
484 
485 TEST_F(FindAllSymbolsTest, IWYUPrivatePragmaTest) {
486   static const char Header[] = R"(
487     // IWYU pragma: private, include "bar.h"
488     struct Bar {
489     };
490   )";
491   static const char Main[] = R"(
492     Bar bar;
493   )";
494   runFindAllSymbols(Header, Main);
495 
496   SymbolInfo Symbol =
497       SymbolInfo("Bar", SymbolInfo::SymbolKind::Class, "bar.h", {});
498   EXPECT_EQ(1, seen(Symbol));
499   EXPECT_EQ(1, used(Symbol));
500 }
501 
502 TEST_F(FindAllSymbolsTest, MacroTest) {
503   static const char Header[] = R"(
504     #define X
505     #define Y 1
506     #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
507   )";
508   static const char Main[] = R"(
509     #ifdef X
510     int main() { return MAX(0,Y); }
511     #endif
512   )";
513   runFindAllSymbols(Header, Main);
514   SymbolInfo Symbol =
515       SymbolInfo("X", SymbolInfo::SymbolKind::Macro, HeaderName, {});
516   EXPECT_EQ(1, seen(Symbol));
517   EXPECT_EQ(1, used(Symbol));
518 
519   Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, HeaderName, {});
520   EXPECT_EQ(1, seen(Symbol));
521   EXPECT_EQ(1, used(Symbol));
522 
523   Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, HeaderName, {});
524   EXPECT_EQ(1, seen(Symbol));
525   EXPECT_EQ(1, used(Symbol));
526 }
527 
528 TEST_F(FindAllSymbolsTest, MacroTestWithIWYU) {
529   static const char Header[] = R"(
530     // IWYU pragma: private, include "bar.h"
531     #define X 1
532     #define Y 1
533     #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
534   )";
535   static const char Main[] = R"(
536     #ifdef X
537     int main() { return MAX(0,Y); }
538     #endif
539   )";
540   runFindAllSymbols(Header, Main);
541   SymbolInfo Symbol =
542       SymbolInfo("X", SymbolInfo::SymbolKind::Macro, "bar.h", {});
543   EXPECT_EQ(1, seen(Symbol));
544   EXPECT_EQ(1, used(Symbol));
545 
546   Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, "bar.h", {});
547   EXPECT_EQ(1, seen(Symbol));
548   EXPECT_EQ(1, used(Symbol));
549 
550   Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, "bar.h", {});
551   EXPECT_EQ(1, seen(Symbol));
552   EXPECT_EQ(1, used(Symbol));
553 }
554 
555 TEST_F(FindAllSymbolsTest, NoFriendTest) {
556   static const char Header[] = R"(
557     class WorstFriend {
558       friend void Friend();
559       friend class BestFriend;
560     };
561   )";
562   runFindAllSymbols(Header, "");
563   SymbolInfo Symbol =
564       SymbolInfo("WorstFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});
565   EXPECT_EQ(1, seen(Symbol));
566 
567   Symbol =
568       SymbolInfo("Friend", SymbolInfo::SymbolKind::Function, HeaderName, {});
569   EXPECT_EQ(0, seen(Symbol));
570 
571   Symbol =
572       SymbolInfo("BestFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});
573   EXPECT_EQ(0, seen(Symbol));
574 }
575 
576 } // namespace find_all_symbols
577 } // namespace clang
578