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